package model

import (
	"config-client-v1/utils/tools"
	"errors"
	"fmt"
)

// Variable 变量表
type Variable struct {
	FrameItem
	ValueStr string    `json:"value_str" gorm:"-"` // PLC变量值使用
	Upper2   *Variable `json:"upper2" gorm:"-"`
	Upper    *Variable `json:"upper" gorm:"-"`
	Lower2   *Variable `json:"lower2" gorm:"-"`
	Lower    *Variable `json:"lower" gorm:"-"`
}

type VariableSlim struct {
	ID        int    `json:"id" gorm:"column:id"`
	Addr      string `json:"addr" gorm:"column:addr"`             // 变量地址
	FieldName string `json:"field_name" gorm:"column:field_name"` // 变量名 (当type是变量时设置)
	SpecType  string `json:"spec_type" gorm:"column:spec_type"`   // 具体数据类型 (uint8, uint16, uint, float32, float64, bool)
}

type VariableModel struct {
	FrameItem
	AlertTypeName string   `json:"alert_type_name" gorm:"-"`
	Origin        string   `json:"origin" gorm:"-"`
	ModuleType    string   `json:"module_type" gorm:"-"`
	RCFormulaName string   `json:"rc_formula_name" gorm:"-"`
	PPEInfo       *PPE     `json:"ppe_info" gorm:"foreignKey:PPEID"` // belongs to 第三方设备
	FSEInfo       *FSEquip `json:"fse_info" gorm:"foreignKey:FSID"`  // belongs to 自研设备
	//FrameInfo *Frame   `json:"frame_info" gorm:"foreignKey:FrameID"` // belongs to 模型
}

type Channel struct {
	FrameItem
	ModuleInfo *Frame `json:"module_info" gorm:"foreignKey:ModuleID"` // belongs to 模型
}

// TableName Variable's table name
func (val *Variable) TableName() string {
	return "frame_item"
}

func (val *VariableSlim) TableName() string {
	return "frame_item"
}

func (val *VariableModel) TableName() string {
	return "frame_item"
}

func (val *Channel) TableName() string {
	return "frame_item"
}

func (val *Variable) CheckParam(mode string, projectID int) (err error) {
	if val.FieldName == "" {
		return errors.New(fmt.Sprintf("%s 变量名不能为空", val.FieldName))
	}
	if val.Endian == "" {
		val.Endian = "big"
	}
	if !AllowEndian[val.Endian] {
		return errors.New(fmt.Sprintf("%s endian 参数无效", val.FieldName))
	}
	switch val.SpecType {
	case "uint8":
	case "int8":
	case "uint16":
	case "int16":
	case "uint32":
	case "int32":
	case "uint64":
	case "int64":
	case "float32":
	case "float64":
	case "bool":
	default:
		err = errors.New(fmt.Sprintf("%s spec_type 参数无效", val.FieldName))
		return
	}
	if mode == "add" { // 新增变量默认都为内部变量, 地址code1取值范围 90~99 , code2取值范围 00~99, code3取值范围 00~99, code4在添加时自动生成
		val.IsInternal = 1
		if val.Code1 == "" || val.Code2 == "" || val.Code3 == "" {
			err = errors.New("新增参数不可为空 code1, code2, code3")
			return
		}
		code1Arr := AllInternalCode1FS()
		if !tools.StrInArray(val.Code1, code1Arr) {
			err = errors.New(fmt.Sprintf("%s code1 值无效", val.FieldName))
			return
		}
		code2Arr := AllCode2()
		if !tools.StrInArray(val.Code2, code2Arr) {
			err = errors.New(fmt.Sprintf("%s code2 值无效", val.FieldName))
			return
		}
		code3Arr := AllCode3()
		if !tools.StrInArray(val.Code3, code3Arr) {
			err = errors.New(fmt.Sprintf("%s code3 值无效", val.FieldName))
			return
		}
	}
	if val.Upper2LimitVarAddr != "" {
		exist, _, _ := AddrExists(projectID, val.Upper2LimitVarAddr)
		if !exist {
			err = errors.New(fmt.Sprintf("%s 上上限变量地址无效", val.FieldName))
			return
		}
	}
	if val.UpperLimitVarAddr != "" {
		exist, _, _ := AddrExists(projectID, val.UpperLimitVarAddr)
		if !exist {
			err = errors.New(fmt.Sprintf("%s 上限变量地址无效", val.FieldName))
			return
		}
	}
	if val.LowerLimitVarAddr != "" {
		exist, _, _ := AddrExists(projectID, val.LowerLimitVarAddr)
		if !exist {
			err = errors.New(fmt.Sprintf("%s 下限变量地址无效", val.FieldName))
			return
		}
	}
	if val.Lower2LimitVarAddr != "" {
		exist, _, _ := AddrExists(projectID, val.Lower2LimitVarAddr)
		if !exist {
			err = errors.New(fmt.Sprintf("%s 下下限变量地址无效", val.FieldName))
			return
		}
	}

	return
}

func AllInternalCode1FS() (arr []string) {
	arr = make([]string, 0)
	for i := 90; i <= 99; i++ {
		arr = append(arr, fmt.Sprintf("%02d", i))
	}
	return
}

func AddrExists(projectID int, addr string) (exist bool, variable *Variable, err error) {
	variable = &Variable{}
	err = DB.Where("project_id = ? AND addr = ?", projectID, addr).Limit(1).Find(variable).Error
	if err != nil {
		return
	}
	if variable.ID == 0 {
		return
	}
	exist = true
	return
}

func (val *Variable) Exists(id int) (exist bool, err error) {
	err = DB.Where("id = ?", id).Limit(1).Find(val).Error
	if err != nil {
		return
	}
	if val.ID == 0 {
		return
	}
	exist = true
	return
}
